home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1122 / 1122.xpi / chrome / tabmixplus.jar / content / tabmixplus / session / sessionStore.js < prev   
Text File  |  2009-09-19  |  36KB  |  910 lines

  1. /*
  2.  * chrome://tabmixplus/content/session/sessionStore.js
  3.  *
  4.  * original code by onemen
  5.  *
  6.  */
  7.  
  8. var TMP_SessionStore = {
  9.    /**
  10.     * @brief       - Add attribute to nsSessionStore persistTabAttribute.
  11.     *
  12.     * @param doInit   a Boolean value - true when we need to init nsISessionStore.
  13.     *
  14.     * @returns        Nothing.
  15.     */
  16.    _persistTabAttributeSet: null,
  17.    persistTabAttribute: function TMP_ss_persistTabAttribute() {
  18.       if (this._persistTabAttributeSet)
  19.          return;
  20.  
  21.       var aTab = gBrowser.mTabContainer.firstChild;
  22.       if (aTab != gBrowser.mCurrentTab) {
  23.          aTab.removeAttribute("visited");
  24.          aTab.removeAttribute("flst_id");
  25.       };
  26.  
  27.       try {
  28.         /*
  29.          * XUL Tab attributes to (re)store
  30.          * Restored in nsSessionStore restoreHistory()
  31.          */
  32.          var _xulAttributes = ["protected", "_locked", "fixed-label", "label-uri", "reload-data", "tabmix_bookmarkId"];
  33.  
  34.          // make TreeStyleTab extension compatible with Tabmix Plus
  35.          if ("TreeStyleTabBrowser" in window)
  36.             _xulAttributes = _xulAttributes.concat(SessionData.tabTSTProperties);
  37.  
  38.          var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
  39.          _xulAttributes.forEach(function(aAttr) {
  40.             ss.persistTabAttribute(aAttr);
  41.          });
  42.  
  43.          this._persistTabAttributeSet = true;
  44.       } catch(ex) {
  45.          tmLog("nsSessionStore could not add Attribute to persistTabAttribute: " + ex + "\n");
  46.       }
  47.    },
  48.  
  49.    /**
  50.     * @brief         make sure that we don't enable both sessionStore and session manager
  51.     *
  52.     * @param msgNo   a Integer value - msg no. to show.
  53.     *
  54.     * @param start   a Boolean value - true if we call this function before startup.
  55.     *
  56.     * @returns       Nothing.
  57.     */
  58.    setService: function TMP_ss_setSessionService(msgNo, start, win) {
  59.       if ("tabmix_setSession" in window || gTabmixPrefs.prefHasUserValue("extensions.tabmix.setDefault"))
  60.          return;
  61.      /*
  62.       * From 2008-03-10 we don't set browser.sessionstore.enabled to false anymore
  63.       * we use nsISessionStore service in TMP.
  64.       * if we use TMP session manager we set all other sessionstore pref to false to disable SessionRestore
  65.       *
  66.       * Bug 449596 û remove the browser.sessionstore.enabled pref
  67.       * so here we don't set it to true, we just clear user pref to the default
  68.       * if the pref exist in firefox this set the pref to true       
  69.       * if the pref don't exist this will remove the pref
  70.       */
  71.       var TMP_manager_enabled = gTabmixPrefs.getBoolPref("extensions.tabmix.sessions.manager");
  72.       var TMP_crashRecovery_enabled = gTabmixPrefs.getBoolPref("extensions.tabmix.sessions.crashRecovery");
  73.       if (!TMP_manager_enabled && !TMP_crashRecovery_enabled) {
  74.          if (gTabmixPrefs.prefHasUserValue("browser.sessionstore.enabled"))
  75.             gTabmixPrefs.clearUserPref("browser.sessionstore.enabled");
  76.          return;
  77.       }
  78.  
  79.       window.tabmix_setSession = true;
  80.       // if session manager extension is install disable TMP session manager
  81.       if ("gSessionManager" in window) {
  82.          // update session manager settings accourding to current tabmix settings
  83.          if (TMP_manager_enabled) {
  84.             gTabmixPrefs.setBoolPref("extensions.tabmix.sessions.manager", false);
  85.             switch (SessionPref.getIntPref("onStart")) {
  86.                case 0:
  87.                   gTabmixPrefs.setIntPref("extensions.sessionmanager.startup", 0);
  88.                   gTabmixPrefs.setIntPref("browser.startup.page", 3);
  89.                   break;
  90.                case 1:
  91.                   gTabmixPrefs.setIntPref("extensions.sessionmanager.startup", 1);
  92.                   break;
  93.                //default: nothing to do
  94.             }
  95.             switch (SessionPref.getIntPref("onClose")) {
  96.                case 0:
  97.                   gTabmixPrefs.setIntPref("extensions.sessionmanager.backup_session", 1);
  98.                   break;
  99.                case 1:
  100.                   gTabmixPrefs.setIntPref("extensions.sessionmanager.backup_session", 2);
  101.                   break;
  102.                default:
  103.                   gTabmixPrefs.setIntPref("extensions.sessionmanager.backup_session", 0);
  104.             }
  105.          }
  106.          if (TMP_crashRecovery_enabled) {
  107.             gTabmixPrefs.setBoolPref("extensions.tabmix.sessions.crashRecovery", false);
  108.             gTabmixPrefs.setBoolPref("browser.sessionstore.resume_from_crash", true);
  109.          }
  110.       }
  111.       else if (!this.getSsessionstoreEnabledPref()) {
  112.          // TMP is the session manager disable all sessionstore pref
  113.          // we only get here when user update from old tabmix version
  114.          // that set browser.sessionstore.enabled to false
  115.          this.setSessionRestore(false);
  116.       }
  117.       else if (this.isSessionStoreEnabled()) {
  118.          // ask the user to choose between TMP session manager and sessionstore
  119.          var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"]
  120.                                   .getService(Ci.nsIPromptService);
  121.          var bundle_session = document.getElementById("bundle_session_manager");
  122.  
  123.          var msg = start ? bundle_session.getString("sm.disable.msg") + "\n\n" : "";
  124.          msg += bundle_session.getString("sm.disable.msg" + msgNo);
  125.          var buttonPressed = promptService.confirmEx(win || window,
  126.                         "TabMix " + bundle_session.getString("sm.title"),
  127.                         msg,
  128.                         (promptService.BUTTON_TITLE_YES * promptService.BUTTON_POS_0)
  129.                         + (promptService.BUTTON_TITLE_NO * promptService.BUTTON_POS_1),
  130.                         null, null, null, null, {});
  131.  
  132.          if ((msgNo == 1 && buttonPressed == 1) || ((msgNo == 2 && buttonPressed == 0)))
  133.             this.setSessionRestore(false);
  134.          else {
  135.             // we don't change any of sessionstore default setting
  136.             // the user will be ask on exit what to do. (browser.warnOnRestart and browser.warnOnQuit are both true on default)
  137.             gTabmixPrefs.setBoolPref("extensions.tabmix.sessions.manager", false);
  138.             gTabmixPrefs.setBoolPref("extensions.tabmix.sessions.crashRecovery", false);
  139.          }
  140.       }
  141.       // when user start new profile or update from firefox 2.0 profile browser.warnOnRestart and browser.warnOnQuit are both true on default
  142.       else if (!gTabmixPrefs.prefHasUserValue("browser.warnOnRestart") ||
  143.                 !gTabmixPrefs.prefHasUserValue("browser.warnOnQuit ")) {
  144.          gTabmixPrefs.setBoolPref("browser.warnOnRestart", false);
  145.          gTabmixPrefs.setBoolPref("browser.warnOnQuit", false);
  146.       }
  147.  
  148.       if (gTabmixPrefs.prefHasUserValue("browser.sessionstore.enabled"))
  149.          gTabmixPrefs.clearUserPref("browser.sessionstore.enabled");
  150.  
  151.       delete window.tabmix_setSession;
  152.    },
  153.  
  154.    // Bug 449596 û remove the browser.sessionstore.enabled pref
  155.    getSsessionstoreEnabledPref: function () {
  156.      if (gIsFirefox35)
  157.        return true;
  158.  
  159.      return gTabmixPrefs.getBoolPref("browser.sessionstore.enabled");
  160.    },
  161.  
  162.    isSessionStoreEnabled: function () {
  163.      return this.getSsessionstoreEnabledPref() &&
  164.         (gTabmixPrefs.getIntPref("browser.startup.page") == 3 || gTabmixPrefs.getBoolPref("browser.sessionstore.resume_from_crash"));
  165.    },
  166.  
  167.    isAfterRestart: function () {
  168.      if (this.getSsessionstoreEnabledPref()) {
  169.        var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
  170.                       getService(Ci.nsISessionStartup);
  171.        // when TMP session manager is enabled this is true only after restart
  172.        return ss.doRestore();
  173.      }
  174.      return false;
  175.    },
  176.  
  177.    setSessionRestore: function (aEnable) {
  178.       gTabmixPrefs.setBoolPref("browser.warnOnRestart", aEnable);
  179.       gTabmixPrefs.setBoolPref("browser.warnOnQuit", aEnable);
  180.       gTabmixPrefs.setBoolPref("browser.sessionstore.resume_from_crash", aEnable);
  181.       if (aEnable)
  182.         gTabmixPrefs.setIntPref("browser.startup.page", 3);
  183.       else if (gTabmixPrefs.getIntPref("browser.startup.page") == 3)
  184.         gTabmixPrefs.setIntPref("browser.startup.page", 1);
  185.    },
  186.  
  187.    /**
  188.     * @brief           get attribute xultab data
  189.     *
  190.     * @param aTabData  an object value - tabData from nsSessionStore
  191.     *
  192.     * @param attrib    attribute name as string
  193.     *
  194.     * @returns         attribute value as string or empty string.
  195.     */
  196.    _getAttribute: function TMP_ss__getAttribute(aTabData, attrib) {
  197.       // tabData.attributes is in use for Firefox 3.5+
  198.       if (aTabData.attributes && attrib in aTabData.attributes)
  199.          return aTabData.attributes[attrib];
  200.  
  201.       // restore attributes from the legacy Firefox 2.0/3.0 format
  202.       if (aTabData.xultab) {
  203.          var xultab = aTabData.xultab.split(" ");
  204.          for ( var i= 0; i < xultab.length; i++ ){
  205.             if (/^([^\s=]+)=(.*)/.test(xultab[i]) && RegExp.$1 == attrib)
  206.                return decodeURI(RegExp.$2);
  207.          }
  208.       }
  209.       return  "";
  210.    },
  211.  
  212.    /**
  213.     * @brief           remove framesets containing wyciwyg URLs (cf. bug 424689 and bug 450595)
  214.     *                  this is fixed for firefox 3.5
  215.     * @param aTabState  an object value - tabState from nsSessionStore
  216.     *
  217.     * @returns         tabState without framesets containing wyciwyg URLs
  218.     */
  219.    removeWyciwyg: function TMP_ss_removeWyciwyg(aTabState) {
  220.       if (gIsFirefox35)
  221.          return false;
  222.  
  223.       var foundWyciwyg = false;
  224.       for (var j = 0; j < aTabState.entries.length; j++) {
  225.         var children = aTabState.entries[j].children;
  226.         if (!children)
  227.           continue;
  228.         for (var i = 0; i < children.length; i++) {
  229.           var child = children[i];
  230.           if (child && (/^wyciwyg:\/\//.test(child.url))) {
  231.             delete aTabState.entries[j].children;
  232.             foundWyciwyg = true;
  233.             break;
  234.           }
  235.         }
  236.       }
  237.       return foundWyciwyg;
  238.    }
  239.  
  240. }
  241.  
  242. var TMP_ClosedTabs = {
  243.    _buttonBroadcaster: null,
  244.    get buttonBroadcaster() {
  245.       if (!this._buttonBroadcaster)
  246.         this._buttonBroadcaster = document.getElementById("tmp_undocloseButton");
  247.       return this._buttonBroadcaster;
  248.    },
  249.  
  250.    /**
  251.     * check to see if nsISessionStore is initialized
  252.     */
  253.    get ssIsON() {
  254.       return "__SSi" in window;
  255.    },
  256.  
  257.    // make btn_undoclose single-functionality or dual-functionality
  258.    setButtonType: function(menuOnly) {
  259.       var buttonType = menuOnly ? "menu" : "menu-button";
  260.       if (this.buttonBroadcaster.getAttribute("type") != buttonType)
  261.          this.buttonBroadcaster.setAttribute("type", buttonType);
  262.    },
  263.  
  264.    setButtonDisableState: function ct_setButtonDisableState(aState) {
  265.       if (typeof(aState) == "undefined")
  266.          aState = this.count == 0;
  267.       aState = aState ? "true" : "false";
  268.       if (this.buttonBroadcaster.getAttribute("disabled") != aState)
  269.          this.buttonBroadcaster.setAttribute("disabled", aState);
  270.    },
  271.  
  272.    _ss: null,
  273.    get ss() {
  274.       if (!this._ss)
  275.          this._ss = Cc["@mozilla.org/browser/sessionstore;1"].
  276.                      getService(Ci.nsISessionStore);
  277.  
  278.       return this._ss;
  279.    },
  280.  
  281.   /**
  282.     * Get closed tabs count
  283.     */
  284.    get count() {
  285.       if (this.ssIsON)
  286.          return this.ss.getClosedTabCount(window);
  287.       else
  288.          return gBrowser.closedTabs.length;
  289.    },
  290.  
  291.   /**
  292.     * Get closed tabs data
  293.     */
  294.    get getClosedTabData() {
  295.       if (this.ssIsON)
  296.          return eval("(" + this.ss.getClosedTabData(window) + ")");
  297.       else
  298.          return gBrowser.closedTabs;
  299.    },
  300.  
  301.    getUrl: function ct_getUrl(aTabData) {
  302.       var history;
  303.       if (this.ssIsON) {
  304.          history = aTabData.state;
  305.          var activeIndex = (history.index || history.entries.length) - 1;
  306.          return history.entries[activeIndex].url;
  307.       }
  308.       history = aTabData.history;
  309.       return history.getEntryAtIndex(history.index, false).URI.spec;
  310.    },
  311.  
  312.   /**
  313.    * @brief           update tab title from user name or bookmark.
  314.    *
  315.    * @param aTabData  an object value - tabData from nsSessionStore
  316.    *
  317.    * @param aUri      string value - url address
  318.    *
  319.    * @returns         tab title - string.
  320.    */
  321.    getTitle: function ct_getTitle(aTabData, aUri) {
  322.       var data = this.ssIsON ? aTabData.state : {xultab: aTabData.properties};
  323.       var fixedLabelUri = TMP_SessionStore._getAttribute(data, "label-uri");
  324.       if (fixedLabelUri == aUri || fixedLabelUri == "*")
  325.          return TMP_SessionStore._getAttribute(data, "fixed-label");
  326.  
  327.       return getTitleFromBookmark(aUri, aTabData.title, TMP_SessionStore._getAttribute(data, "tabmix_bookmarkId"));
  328.    },
  329.  
  330.    /* .......... functions for closedtabs list menu and context menu .......... */
  331.  
  332.    populateUndoSubmenu: function ct_populateUndoSubmenu(aPopup) {
  333.       if (isAfterCtrlClick(aPopup.parentNode))
  334.          return false;
  335.  
  336.       beforeCommonList(aPopup);
  337.  
  338.       // populate menu
  339.       var closedTabs = this.getClosedTabData;
  340.       for (var i = 0; i < closedTabs.length; i++) {
  341.          var m = document.createElement("menuitem");
  342.          var tabData = closedTabs[i];
  343.          // Grab the title and uri (make the uri friendly text)
  344.          var url = this.getUrl(tabData);
  345.          var title = this.getTitle(tabData, url);
  346.          var _uri = makeURI(url);
  347.          if ( _uri.scheme == "about" && title == "" )
  348.             url = title = "about:blank";
  349.          else try {
  350.             url = _uri.scheme + ":\/\/" + _uri.hostPort + _uri.path;
  351.          } catch (e) {
  352.             url = title;
  353.          }
  354.          var label = title ? title : url;
  355.          var count = (i<9 ? "  " : "") + (i + 1) + ": ";
  356.          m.setAttribute("label", count + label);
  357.          m.setAttribute("tooltiptext", label);
  358.          m.setAttribute("statustext", url);
  359.  
  360.          var iconURL = tabData.image;
  361.          if (iconURL) {
  362.             if (/^https?:/.test(iconURL))
  363.                iconURL = "moz-anno:favicon:" + iconURL;
  364.             m.setAttribute("image", iconURL);
  365.          }
  366.          if (i+1 < 10)
  367.            m.setAttribute("accesskey", i+1);
  368.          else if (i+1 == 10)
  369.            m.setAttribute("accesskey", 0);
  370.          m.setAttribute("class", "menuitem-iconic bookmark-item");
  371.          m.setAttribute("value", i);
  372.          m.setAttribute("oncommand", "TMP_ClosedTabs.restoreTab('original', " + i + "); event.stopPropagation();");
  373.          m.addEventListener("click", TMP_ClosedTabs.checkForMiddleClick, false);
  374.          if (i == 0)
  375.             m.setAttribute("key", "key_undoCloseTab");
  376.          aPopup.appendChild(m);
  377.       }
  378.  
  379.       aPopup.appendChild(document.createElement("menuseparator"));
  380.       // "Clear Closed Tabs List"
  381.       var strings = document.getElementById("tmp-string-bundle");
  382.       m = aPopup.appendChild(document.createElement("menuitem"));
  383.       m.setAttribute("id", "clearClosedTabsList");
  384.       m.setAttribute("label", strings.getString("undoclosetab.clear.label"));
  385.       m.setAttribute("accesskey", strings.getString("undoclosetab.clear.accesskey"));
  386.       m.setAttribute("value", -1);
  387.       m.setAttribute("oncommand", "TMP_ClosedTabs.restoreTab('original', -1); event.stopPropagation();");
  388.  
  389.       // "Restore All Tabs"
  390.       m = aPopup.appendChild(document.createElement("menuitem"));
  391.       m.setAttribute("id", "restoreAllClosedTabs");
  392.       strings = gNavigatorBundle;
  393.       if (gIsFirefox36) {
  394.         m.setAttribute("label", strings.getString("menuRestoreAllTabs.label"));
  395.         m.setAttribute("accesskey", strings.getString("menuRestoreAllTabs.accesskey"));
  396.       }
  397.       else {
  398.         m.setAttribute("label", strings.getString("menuOpenAllInTabs.label"));
  399.         m.setAttribute("accesskey", strings.getString("menuOpenAllInTabs.accesskey"));
  400.       }
  401.       m.setAttribute("value", -2);
  402.       m.setAttribute("oncommand", "TMP_ClosedTabs.restoreTab('original', -2); event.stopPropagation();");
  403.  
  404.       return true;
  405.    },
  406.  
  407.    checkForMiddleClick: function ct_checkForMiddleClick(aEvent) {
  408.       if (aEvent.button != 1)
  409.          return;
  410.  
  411.       aEvent.stopPropagation();
  412.       var index = aEvent.originalTarget.value;
  413.       if (index < 0)
  414.          return;
  415.  
  416.       var where = tabxPrefs.getBoolPref("middleclickDelete") ? 'delete' : 'tab';
  417.       TMP_ClosedTabs.restoreTab(where, index);
  418.       var popup = aEvent.originalTarget.parentNode;
  419.       if (TMP_ClosedTabs.count > 0)
  420.          TMP_ClosedTabs.populateUndoSubmenu(popup);
  421.       else {
  422.          popup.hidePopup();
  423.          if (popup.parentNode.id != "btn_undoclose")
  424.             popup.parentNode.parentNode.hidePopup();
  425.       }
  426.    },
  427.  
  428.    addBookmarks: function ct_addBookmarks(index) {
  429.       var tabData = this.getClosedTabData[index];
  430.       var url = this.getUrl(tabData);
  431.       var title = this.getTitle(tabData, url);
  432.       PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId, url, title);
  433.    },
  434.  
  435.    copyTabUrl: function ct_copyTabUrl(index) {
  436.       var tabData = this.getClosedTabData[index];
  437.       var url = this.getUrl(tabData);
  438.       var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
  439.                       .getService(Components.interfaces.nsIClipboardHelper);
  440.  
  441.       clipboard.copyString(url);
  442.    },
  443.  
  444.    restoreTab: function ct_restoreTab(aWhere, aIndex) {
  445.       if (!this.ssIsON) {
  446.          _restoreTab(aWhere, aIndex);
  447.          return;
  448.       }
  449.  
  450.       switch (aWhere) {
  451.          case "window":
  452.             this.SSS_restoreToNewWindow(aIndex);
  453.             break;
  454.          case "delete":
  455.             this.getClosedTabAtIndex(aIndex);
  456.             break;
  457.          case "original":
  458.             if (aIndex == -1) {
  459.                this.getClosedTabAtIndex(aIndex);
  460.                return;
  461.             }
  462.             else if (aIndex == -2) {
  463.                this.SSS_restoerAllClosedTabs();
  464.                return;
  465.             }
  466.             // else do the default
  467.          default:
  468.             this.SSS_undoCloseTab(aIndex, aWhere, true);
  469.       }
  470.    },
  471.  
  472.   /**
  473.    * @brief           fetch the data of closed tab, while removing it from the array
  474.    * @param aIndex    a Integer value - 0 or grater index to remove
  475.    *                  other value empty the list.
  476.    * @returns         closed tab data at aIndex.
  477.    *
  478.    * we can use ss.forgetClosedRab(index) from Firefox ? after ?
  479.    *
  480.    */
  481.    getClosedTabAtIndex: function ct_getClosedTabAtIndex(aIndex) {
  482.       // update our session data
  483.       // we don't use gBrowser.closedTabs when sessionStore is on
  484.       var updateRDF = SessionManager.enableBackup && SessionPref.getBoolPref("save.closedtabs");
  485.       if (updateRDF) {
  486.         if (aIndex >= 0)
  487.            SessionManager.deleteClosedtabAt(this.count - aIndex);
  488.         else
  489.            SessionManager.deleteWinClosedtabs(gThisWin);
  490.       }
  491.  
  492.       var closedTab;
  493.       var state = { windows: [], _firstTabs: true };
  494.       state.windows[0] = {tabs:[], _closedTabs: [] };
  495.       // if aIndex is not > 0 we just past empy list to setWindowState
  496.       // it's like remove all closed tabs from the list
  497.       if (aIndex >= 0) {
  498.          state.windows[0]._closedTabs = this.getClosedTabData;
  499.          // purge closed tab at aIndex
  500.          closedTab = state.windows[0]._closedTabs.splice(aIndex, 1).shift();
  501.       }
  502.  
  503.       // replace existing _closedTabs
  504.       try {
  505.         this.ss.setWindowState(window, state.toSource(), false);
  506.       } catch (e) {}
  507.  
  508.       this.setButtonDisableState();
  509.       return closedTab;
  510.    },
  511.  
  512.    SSS_restoreToNewWindow: function ct_restoreToNewWindow(aIndex) {
  513.       var tabData = this.getClosedTabAtIndex(aIndex);
  514.       // we past the current tab as reference to this window
  515.       return gBrowser.duplicateInWindow(gBrowser.mCurrentTab, null, tabData);
  516.    },
  517.  
  518.    SSS_restoerAllClosedTabs: function ct_SSS_restoerAllClosedTabs() {
  519.       var closedTabCount = this.count;
  520.       if (!PlacesController.prototype._confirmOpenTabs(closedTabCount))
  521.          return;
  522.  
  523.       this.setButtonDisableState(true);
  524.  
  525.       var aTab, blankTab;
  526.       // catch blank tab
  527.       var blankTabs = [];
  528.       for (var i = 0; i < gBrowser.mTabs.length ; i++) {
  529.          if (gBrowser.isBlankNotBusyTab(gBrowser.mTabs[i]))
  530.             blankTabs.push(gBrowser.mTabs[i]);
  531.       }
  532.  
  533.       for (i = 0; i < closedTabCount; i++) {
  534.          blankTab = blankTabs.pop();
  535.          this.SSS_undoCloseTab(0, "original", i==0, blankTab);
  536.       }
  537.  
  538.       // remove unused blank tabs
  539.       while(blankTabs.length > 0){
  540.          blankTab = blankTabs.pop();
  541.          blankTab.collapsed = true;
  542.          gBrowser.removeTab(blankTab, false);
  543.       }
  544.  
  545.       gBrowser.mTabContainer.nextTab = 1;
  546.    },
  547.  
  548.    SSS_undoCloseTab: function ct_SSS_undoCloseTab(aIndex, aWhere, aSelectRestoredTab, aTabToRemove) {
  549.       if (!tabxPrefs.getBoolPref("undoClose") || this.count == 0)
  550.          return null;
  551.  
  552.       // get tab data
  553.       var tabData = this.getClosedTabAtIndex(aIndex);
  554.       TMP_SessionStore.removeWyciwyg(tabData.state);
  555.  
  556.       var cTab = gBrowser.mCurrentTab;
  557.       if (aWhere == "current") {
  558.          aTabToRemove = cTab;
  559.          tabData.pos = cTab._tPos;
  560.       }
  561.       else if (typeof(aTabToRemove) == "undefined" && gBrowser.isBlankNotBusyTab(cTab))
  562.          aTabToRemove = cTab;
  563.  
  564.       if (aTabToRemove)
  565.          aTabToRemove.collapsed = true;
  566.  
  567.       var newTab = gBrowser.addTab("about:blank");
  568.       // if tababr is hidden when there is only one tab and
  569.       // we replace that tab with new one close the current tab fast so the tab bar don't have time to reveale
  570.       if (aTabToRemove)
  571.          gBrowser.removeTab(aTabToRemove);
  572.       // add restored tab to current window
  573.       this.ss.setTabState(newTab, tabData.state.toSource());
  574.  
  575.       // after we open new tab we only need to fix position if this is true
  576.       var restorePosition = tabxPrefs.getBoolPref("undoClosePosition");
  577.       if ( aWhere == "current" || (aWhere == "original" && restorePosition) ) {
  578.          gBrowser.TMmoveTabTo(newTab, Math.min(gBrowser.mTabs.length - 1, tabData.pos), 1);
  579.       }
  580.       else if (aWhere != "end")
  581.          // we don't call TMP_openTabNext from add tab if it called from sss_undoCloseTab
  582.          gBrowser.TMP_openTabNext(newTab);
  583.  
  584.       if (aSelectRestoredTab) {
  585.          content.focus();
  586.          gBrowser.TMP_selectNewForegroundTab(newTab, false, null, false);
  587.       }
  588.  
  589.       return newTab;
  590.    },
  591.  
  592.    TMP_undoCloseTab: function ct_TMP_undoCloseTab() {
  593.       if( !tabxPrefs.getBoolPref("undoClose" ) || !gBrowser.closedTabs.length )
  594.          return null;
  595.  
  596.       var tabData = getClosedTab("original", 0);
  597.       return gBrowser.restoreTab(tabData.pos, tabData.history, tabData.properties, tabData.scroll);
  598.    },
  599.  
  600.    undoCloseTab: function ct_undoCloseTab(aIndex, aWhere) {
  601.       var newTab;
  602.       if (this.ssIsON)
  603.          newTab = this.SSS_undoCloseTab(aIndex || 0, aWhere || "original", true);
  604.       else
  605.          newTab = this.TMP_undoCloseTab();
  606.  
  607.       return newTab;
  608.    }
  609.  
  610. }
  611.  
  612. var convertSession = {
  613.    get _prompt() {
  614.       return Cc["@mozilla.org/embedcomp/prompt-service;1"]
  615.                             .getService(Ci.nsIPromptService);
  616.    },
  617.  
  618.    get getTitle() {
  619.       return document.getElementById("tmp-string-bundle").getString("incompatible.title") + " - " +
  620.                 document.getElementById("bundle_session_manager").getString("sm.title");
  621.    },
  622.  
  623.    getString: function cs_getString(aEntity) {
  624.       return document.getElementById("bundle_session_manager").
  625.          getString("sm.extension.convert." + aEntity);
  626.    },
  627.  
  628.    startup: function cs_startup() {
  629.       var _afterTabduplicated = "tabmix_afterTabduplicated" in window && window.tabmix_afterTabduplicated;
  630.       var isFirstWindow = "gSessionManager" in window && numberOfWindows() == 1 && !_afterTabduplicated;
  631.       if (!isFirstWindow)
  632.          return;
  633.  
  634.       var sessions = SessionManager.getSessionList();
  635.       if (!sessions)
  636.          return;
  637.  
  638.       if(SessionManager.nodeHasArc("rdf:gSessionManager", "status"))
  639.          return;
  640.  
  641.       SessionManager.setLiteral("rdf:gSessionManager", "status", "converted");
  642.       SessionManager.saveStateDelayed();
  643.  
  644.       var rv = this.confirm(this.getString("msg1") + "\n\n" + this.getString("msg2"));
  645.       if (rv == 0)
  646.          this.doConvert(sessions);
  647.    },
  648.  
  649.    selectFile: function cs_selectFile(aWindow) {
  650.       const nsIFilePicker = Ci.nsIFilePicker;
  651.       var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  652.  
  653.       fp.init(aWindow, this.getString("selectfile"), nsIFilePicker.modeOpen);
  654.       fp.defaultString="session.rdf";
  655.       fp.appendFilter(this.getString("rdffiles"), "*.rdf");
  656.       fp.appendFilter(this.getString("sessionfiles"), "*session*.*");
  657.       fp.appendFilters(nsIFilePicker.filterText | nsIFilePicker.filterAll);
  658.  
  659.       if (fp.show() != nsIFilePicker.returnOK)
  660.          return;
  661.  
  662.       this.convertFile(fp.fileURL.spec);
  663.    },
  664.  
  665.    convertFile: function cs_convertFile(aFileUri) {
  666.       var sessions;
  667.       if (aFileUri) {
  668.          try {
  669.             var tmpDATASource = SessionManager.DATASource;
  670.             SessionManager.DATASource = SessionManager.RDFService.GetDataSourceBlocking(aFileUri);
  671.             sessions = SessionManager.getSessionList();
  672.          } catch (ex) { // corrupted session.rdf
  673.             SessionManager.DATASource = tmpDATASource;
  674.             TMP_ASSERT(ex);
  675.          }
  676.       }
  677.       else
  678.          sessions = SessionManager.getSessionList();
  679.  
  680.       var msg;
  681.       if (!sessions) {
  682.          this._prompt.alert(null, this.getTitle, this.getString("nosessions"));
  683.          return;
  684.       }
  685.       var rv = 0;
  686.       if(SessionManager.nodeHasArc("rdf:gSessionManager", "status")) {
  687.          rv = this.confirm(this.getString("alreadyconverted") + "\n\n" + this.getString("doitagain"));
  688.       }
  689.       else {
  690.          SessionManager.setLiteral("rdf:gSessionManager", "status", "converted");
  691.          SessionManager.saveStateDelayed();
  692.       }
  693.       if (rv == 0)
  694.          this.doConvert(sessions);
  695.  
  696.       if (tmpDATASource)
  697.          SessionManager.DATASource = tmpDATASource;
  698.    },
  699.  
  700.    confirm: function cs_confirm(aMsg) {
  701.       var promptService = this._prompt;
  702.       return promptService.confirmEx(null,
  703.                            this.getTitle,
  704.                            aMsg,
  705.                            (promptService.BUTTON_TITLE_YES * promptService.BUTTON_POS_0)
  706.                            + (promptService.BUTTON_TITLE_NO * promptService.BUTTON_POS_1),
  707.                            null, null, null, null, {});
  708.    },
  709.  
  710.    doConvert: function cs_doConvert(sessions) {
  711.       var sessionsPath = sessions.path.push(gSessionPath[3]);
  712.       var sessionsName = sessions.list.push("Crashed Session");
  713.       var _count = 0, tabsCount;
  714.       this.sessionList = [];
  715.       for (var i = 0; i < sessions.path.length; i++ ) {
  716.          var sessionState = this.getSessionState(sessions.path[i]);
  717.          // get timestamp from nameExt property
  718.          var dateString = "", fileDate;
  719.          var nameExt = SessionManager.getLiteralValue(sessions.path[i], "nameExt");
  720.          if (nameExt) {
  721.             var date = nameExt.substr(nameExt.length - 20, 10);
  722.             var time = nameExt.substr(nameExt.length - 9, 8);
  723.             fileDate = " (" + date.split("/").join("-") + ")";
  724.             dateString = " (" + date.split("/").join("-") + " " + time.substr(0, time.length - 3) + ")";
  725.             var _time = time.split(":");
  726.             var timestamp = new Date(date).valueOf() + 3600*_time[0] + 60*_time[1] + 1*_time[2];
  727.          }
  728.          var sessionName = unescape(sessions.list[i]);
  729.          var fileName = gSessionManager.makeFileName("Tabmix - " + sessionName + fileDate);
  730.          tabsCount = sessionState.tabsCount;
  731.          delete sessionState.tabsCount;
  732.          if (this.save(sessionState, timestamp, "[ Tabmix ] " + sessionName + dateString, fileName, tabsCount)) {
  733.             _count++;
  734.             var item = { name: sessionName + dateString, fileName: fileName, autosave: false, windows: sessionState.windows.length, tabs: tabsCount, group: "[Tabmix]" };
  735.             this.sessionList.push(item);
  736.           }
  737.       }
  738.  
  739.       var msg;
  740.       if (_count == 0) {
  741.          this._prompt.alert(null, this.getTitle, this.getString("unable"));
  742.          return;
  743.       }
  744.       else if (_count > 1)
  745.          msg = _count + " " + this.getString("many") + "\n" + this.getString("rename");
  746.       else
  747.          msg = this.getString("one") + "\n" + this.getString("rename");
  748.  
  749.       var sessionToDelete = gSessionManager.selectSession(msg, gSessionManager._string("remove_session_ok"),
  750.                                                    { multiSelect: true, remove: true },
  751.                                                    function() { return convertSession.sessionList;});
  752.       delete this.sessionList;
  753.       if (sessionToDelete)
  754.          gSessionManager.remove(sessionToDelete);
  755.    },
  756.  
  757.    save: function cs_save(aSession, aTimestamp, aName, aFileName, aTabsCount) {
  758.       if (aSession.windows.length == 0)
  759.          return false;
  760.  
  761.       if (!aSession.session)
  762.          aSession.session = { state:"stop" };
  763.       var oState = "[SessionManager]\nname=" + aName + "\ntimestamp=" + aTimestamp +
  764.                        "\nautosave=false\tcount=" + aSession.windows.length + "/" + aTabsCount + "\tgroup=[Tabmix]\n" + aSession.toSource();
  765.       var file = gSessionManager.getSessionDir(gSessionManager.makeFileName(aName));
  766.       try {
  767.          file = gSessionManager.getSessionDir(aFileName, true);
  768.          gSessionManager.writeFile(file, oState);
  769.       }
  770.       catch (ex) {
  771.          TMP_ASSERT(ex);
  772.          return false;
  773.       }
  774.       return true;
  775.    },
  776.  
  777.    getSessionState: function cs_getSessionState(aPath) {
  778.       var _windows = [], tabsCount = 0;
  779.       var sessionEnum = SessionManager.initContainer(aPath).GetElements();
  780.       while (sessionEnum.hasMoreElements()) {
  781.          var rdfNodeWindow = sessionEnum.getNext();
  782.          if (rdfNodeWindow instanceof tmRDFResource) {
  783.             var windowPath = rdfNodeWindow.QueryInterface(tmRDFResource).Value;
  784.             if (SessionManager.nodeHasArc(windowPath, "dontLoad"))
  785.                continue;
  786.             var aWindowState = this.getWindowState(rdfNodeWindow);
  787.             if (aWindowState) {// don't save empty windows
  788.                _windows.push(aWindowState);
  789.                tabsCount += aWindowState.tabs.length;
  790.             }
  791.          }
  792.       }
  793.       return { windows: _windows, tabsCount: tabsCount };
  794.    },
  795.  
  796.    getWindowState: function cs_getWindowState(rdfNodeWindow) {
  797.       var state = { tabs: [], selected: 0, _closedTabs: [] };
  798.  
  799.       var rdfNodeTabs = SessionManager.getResource(rdfNodeWindow, "tabs");
  800.       if (!(rdfNodeTabs instanceof tmRDFResource) || SessionManager.containerEmpty(rdfNodeTabs)) {
  801.          return null;
  802.       }
  803.       state.tabs = this.getTabsState(rdfNodeTabs);
  804.       state._closedTabs = this.getClosedTabsState(SessionManager.getResource(rdfNodeWindow, "closedtabs"));
  805.       state.selected = SessionManager.getIntValue(rdfNodeWindow, "selectedIndex") + 1;
  806.       // we don't save windowState in Tabmix, just get the current windowState for all the sessions
  807.       state.sizemode = (window.windowState == window.STATE_MAXIMIZED) ? "maximized" : "normal";
  808.       return state;
  809.    },
  810.  
  811.    getTabsState: function cs_getTabsState(rdfNodeTabs) {
  812.       var _tabs = [], tabsData = [];
  813.       var tabsEnum = SessionManager.initContainer(rdfNodeTabs).GetElements();
  814.       while (tabsEnum.hasMoreElements()) {
  815.          var rdfNodeTab = tabsEnum.getNext();
  816.          if (rdfNodeTab instanceof tmRDFResource) {
  817.             var tabPos = SessionManager.getIntValue(rdfNodeTab, "tabPos");
  818.             tabsData.push([tabPos, rdfNodeTab]);
  819.          }
  820.       }
  821.       tabsData.sort(SessionManager.sortByColumn(0 ,true));
  822.       for (var i = 0; i < tabsData.length ; i++)
  823.          _tabs.push(this.getTabState(tabsData[i][1]));
  824.  
  825.       return _tabs;
  826.    },
  827.  
  828.    getClosedTabsState: function cs_getClosedTabsState(rdfNodeTabs) {
  829.       var _tabs = [];
  830.       var tabsEnum = SessionManager.initContainer(rdfNodeTabs).GetElements();
  831.       while (tabsEnum.hasMoreElements()) {
  832.          var rdfNodeTab = tabsEnum.getNext();
  833.          if (rdfNodeTab instanceof tmRDFResource) {
  834.             var closedTab = {};
  835.             closedTab.state = this.getTabState(rdfNodeTab);
  836.             closedTab.title = closedTab.state.entries[closedTab.state.index - 1].title;
  837.             closedTab.image = SessionManager.getLiteralValue(rdfNodeTab, "image");
  838.             closedTab.pos = SessionManager.getIntValue(rdfNodeTab, "tabPos");
  839.             // we use in the RDF revers order
  840.             _tabs.unshift(closedTab);
  841.          }
  842.       }
  843.       return _tabs;
  844.    },
  845.  
  846.    getTabState: function cs_getTabState(rdfNodeTab) {
  847.       var tabData = {entries:[], index: 0, zoom: 1, disallow:"", extData: null, text:""};
  848.       tabData.entries = this.getHistoryState(rdfNodeTab);
  849.       tabData.index = SessionManager.getIntValue(rdfNodeTab, "index") + 1;
  850.       tabData.zoom = SessionManager.getLiteralValue(rdfNodeTab, "scroll").split(",")[2];
  851.       var properties = SessionManager.getLiteralValue(rdfNodeTab, "properties");
  852.       var tabAttribute = ["Images","Subframes","MetaRedirects","Plugins","Javascript"];
  853.  
  854.       var booleanAttrLength = SessionData.tabAttribute.length + SessionData.docShellItems.length;
  855.       var tabProperties = properties.substr(0, booleanAttrLength);
  856.       var disallow = [];
  857.       for (var j = 0; j < tabAttribute.length; j++ ) {
  858.          if (tabProperties.charAt(j+2) != "1")
  859.             disallow.push(tabAttribute[j]);
  860.       }
  861.       tabData.disallow = disallow.join(",");
  862.       var xultab = [];
  863.       // xultab replace in firefox 3.5+ with tabData.attributes
  864.       // but nsSessionStore can still read xultab
  865.       if (gIsFirefox35) {
  866.          tabData.attributes = {};
  867.          if (tabProperties.charAt(0) == "1" && properties.indexOf("protected=") == -1)
  868.             tabData.attributes["protected"] = "true";
  869.          if (properties.indexOf("_locked=") == -1)
  870.             tabData.attributes["_locked"] = (tabProperties.charAt(1) == "1");
  871.  
  872.          if (properties.length > booleanAttrLength) {
  873.             properties = properties.substr(booleanAttrLength + 1).split(" ");
  874.             properties.forEach(function(aAttr) {
  875.               if (/^([^\s=]+)=(.*)/.test(aAttr)) {
  876.                 tabData.attributes[RegExp.$1] = RegExp.$2;
  877.               }
  878.             });
  879.          }
  880.       }
  881.       else {
  882.          if (tabProperties.charAt(0) == "1" && properties.indexOf("protected=") == -1)
  883.             xultab.push("protected=true");
  884.          if (properties.indexOf("_locked=") == -1)
  885.             xultab.push("_locked=" + (tabProperties.charAt(1) == "1"));
  886.          tabData.xultab = xultab.join(" ");
  887.          if (properties.length > booleanAttrLength)
  888.            tabData.xultab += properties.substr(booleanAttrLength);
  889.       }
  890.       return tabData;
  891.    },
  892.  
  893.    getHistoryState: function cs_getHistoryState(rdfNodeTab) {
  894.       var tmpData = SessionManager.getLiteralValue(rdfNodeTab, "history").split("|-|");
  895.       var sep = tmpData.shift(); // remove seperator from data
  896.       var historyData = tmpData.join("|-|").split(sep);
  897.       var historyCount = historyData.length/3;
  898.       var entries = [];
  899.       for ( var i = 0; i < historyCount; i++ ){
  900.          var entry = { url:"", children:[], ID: 0};
  901.          var index = i * 3;
  902.          entry.url = historyData[index + 1];
  903.          entry.title = unescape(historyData[index]);
  904.          entry.scroll = historyData[index + 2];
  905.          entries.push(entry);
  906.       }
  907.       return entries;
  908.    }
  909. }
  910.